
//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** @author  John Miller, Michael E. Cotterell
 *  @version 1.0
 *  @see     LICENSE (MIT style license file).
 */

package scalation.stat

import math.sqrt

import scalation.linalgebra.VectorD
import scalation.random.{Quantile, Uniform}
import scalation.util.Error

//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/** This class is used to collect values and compute sample statistics on them
 *  (e.g., Waiting Time) using the Method of Batch Means (MBM).
 *  @param name      the name for this statistic (e.g., WatingTime or tellerQ)
 *  @param batchSize 
 *  @param unbiased  whether the estimators are restricted to be unbiased.
 */
class BatchStatistic(name: String, val batchSize: Int = 100, unbiased: Boolean = false) 
      extends Statistic(name, unbiased) with Error
{

    /** The batch vector used for this batch statistic.
    */
    protected var _batchVec = new BatchVec("%s-batchVec".format(name), batchSize)
    
    /** The denominator is one less for unbiased vs. maximum likelihood estimators
     */
    private def den = (if (unbiased) _batchVec.len - 1.0 else _batchVec.len).toDouble

    def nBatches = _batchVec.nBatches
    def target   = _batchVec.target
    def gamma    = _batchVec.gamma

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Tally the next value and update accumulators.
     *  @param x  the value to tally
     */
    override def tally (x: Double) = _batchVec.tally(x)

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Get the number of samples.
     */
    override def num: Int = _batchVec.len

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Get the minimum value in sample.
     */
    override def min: Double = if (num == 0) 0. else _batchVec.min

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Get the maximum value in sample.
     */
    override def max: Double = _batchVec.max

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute/estimate the sample mean.
     */
    override def mean: Double = if (num == 0) 0. else _batchVec.mean

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute/estimate the sample variance.  The denominator is one less for
     *  unbiased (n-1) vs. maximum likelihood (n) estimators.  Also use n for
     *  population variance.
     */
    override def variance: Double = if (n == 0) 0. else _batchVec.variance

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute/estimate the sample standard deviation.
     */
    override def stddev: Double = _batchVec.stddev

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute/estimate the mean square (ms).
     */
    override def ms: Double = _batchVec.ms

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute/estimate the root mean square (rms).
     */
    override def rms: Double = _batchVec.rms

    //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    /** Compute the confidence interval half-width for the given confidence level.
     *  @param p  the confidence level
     */
    override def interval (p: Double = .95): Double = _batchVec.interval(p)

    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /** Determine if the batches are sufficiently uncorrelated.
     *  @param threshold  the cut-off value to be considered uncorrelated
     */
    def uncorrelated (threshold: Double = 0.2) = true // _batchVec.uncorrelated(threshold)

    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /** Determine if the Confidence Interval (CI) on the grand mean is tight enough.
     *  @param precision  the cut-off value for CI to be considered tight
     *  @param p          the confidence level
     */
    def precise (precision: Double = 0.3, p: Double = 0.95) = _batchVec._precise //.precise(precision, p)

    override def toString: String = 
    {
        "| %4d | %9.3f | %9.3f | %9.3f | %9.3f | %9.3f | batches = %d, size = %d".format (num, min, max, mean, stddev, interval (), _batchVec.nBatches, _batchVec.bSize)
    } // toString

} // BatchStat class


